package org.apereo.cas.configuration.model.core.authentication;

import lombok.Getter;
import lombok.Setter;
import org.apereo.cas.configuration.support.RequiresModule;
import org.apereo.cas.configuration.support.SpringResourceProperties;
import org.springframework.util.LinkedCaseInsensitiveMap;

import javax.security.auth.login.LoginException;
import java.io.Serializable;
import java.util.Map;

/**
 * Configuration properties class for password.policy.
 *
 * @author Dmitriy Kopylenko
 * @since 5.0.0
 */
@RequiresModule(name = "cas-server-core-authentication", automated = true)
@Getter
@Setter
public class PasswordPolicyProperties implements Serializable {
    private static final long serialVersionUID = -3878237508646993100L;

    public enum PasswordPolicyHandlingOptions {
        /**
         * Default option to handle policy changes.
         * 处理策略更改的默认选项
         */
        DEFAULT,
        /**
         * Handle account password policies via Groovy.
         * 通过Groovy处理帐户密码策略。
         */
        GROOVY,
        /**
         * Strategy to only activate password policy
         * if the authentication response code is not blacklisted.
         * 仅激活密码策略的策略
         * 如果验证响应代码未列入黑名单。
         */
        REJECT_RESULT_CODE
    }

    /**
     * Decide how authentication should handle password policy changes.
     * Acceptable values are:
     * <ul>
     * <li>{@code DEFAULT}: Default password policy rules handling account states.</li>
     * <li>{@code GROOVY}: Handle account changes and warnings via Groovy scripts</li>
     * <li>{@code REJECT_RESULT_CODE}: Handle account state only if the authentication result code isn't blocked</li>
     * </ul>
     */
    private PasswordPolicyHandlingOptions strategy = PasswordPolicyHandlingOptions.DEFAULT;

    /**
     * Key-value structure (Map) that indicates a list of boolean attributes as keys.
     * If either attribute value is true, indicating an account state is flagged,
     * the corresponding error can be thrown.
     * Example {@code accountLocked=javax.security.auth.login.AccountLockedException}
     * 键值结构（Map），表示布尔属性的列表作为键。
     * 如果其中一个属性值为true，则表示已标记帐户状态，
     * 可以引发相应的错误。
     *
     * *示例{@code accountLocked=javax.security.auth.login.AccountLockedException}
     */
    private Map<String, Class<LoginException>> policyAttributes = new LinkedCaseInsensitiveMap<>();

    /**
     * Whether password policy should be enabled.
     * 密码代理是否被启用
     */
    private boolean enabled = true;

    /**
     * Indicates whether account state handling should be enabled to process
     * warnings or errors reported back from the authentication response, produced by the source.
     * 指示是否应启用帐户状态处理以进行处理
     * 从源生成的身份验证响应返回的警告或错误。
     */
    private boolean accountStateHandlingEnabled = true;

    /**
     * When dealing with FreeIPA, indicates the number of allows login failures.
     * 在处理FreeIPA时，指示允许登录失败的次数。
     */
    private int loginFailures = 5;

    /**
     * Used by an account state handling policy that only calculates account warnings
     * in case the entry carries an attribute {@link #warningAttributeName}
     * whose value matches this field.
     * 由仅计算帐户警告的帐户状态处理策略使用
     * 如果条目带有属性{@link#warningAttributeName}
     * 其值与此字段匹配。
     */
    private String warningAttributeValue;

    /**
     * Used by an account state handling policy that only calculates account warnings
     * in case the entry carries this attribute.
     * 由仅计算帐户警告的帐户状态处理策略使用
     * 以防条目携带此属性。
     */
    private String warningAttributeName;

    /**
     * Indicates if warning should be displayed, when the ldap attribute value
     * matches the {@link #warningAttributeValue}.
     * 指示当ldap属性值
     * 匹配{@link#warningAttributeValue}。
     */
    private boolean displayWarningOnMatch = true;

    /**
     * Always display the password expiration warning regardless.
     * 始终显示密码过期警告。
     */
    private boolean warnAll;

    /**
     * This is used to calculate
     * a warning period to see if account expiry is within the calculated window.
     * 这是用来计算的
     * 一个警告期，用于查看帐户到期是否在计算窗口内。
     */
    private int warningDays = 30;

    /**
     * Handle password policy via Groovy script.
     */
    private Groovy groovy = new Groovy();

    @RequiresModule(name = "cas-server-core-authentication", automated = true)
    @Getter
    @Setter
    public static class Groovy extends SpringResourceProperties {
        private static final long serialVersionUID = 8079027843747126083L;
    }
}
